Hệ thống quản lý phòng khám trực tuyến bằng PHP

1 <?php
2 /**
3  * CodeIgniter
4  *
5  * An open source application development framework
for PHP 4.3.2 or newer
6  *
7  * @package CodeIgniter
8  * @author ExpressionEngine Dev Team
9  * @copyright Copyright (c)
2008 - 2009, EllisLab, Inc.
10  * @license http://codeigniter.com/user_guide/license.html
11  * @link http://codeigniter.com
12  * @since Version
1.0
13  * @filesource
14  */
15
16 // ------------------------------------------------------------------------
17
18 /**
19  * Input Class
20  *
21  * Pre-processes
global input data for security
22  *
23  * @package CodeIgniter
24  * @subpackage Libraries
25  * @category Input
26  * @author ExpressionEngine Dev Team
27  * @link http://codeigniter.com/user_guide/libraries/input.html
28  */

29 class
CI_Input {
30     
var $use_xss_clean = FALSE;
31     
var $xss_hash = '';
32     
var $ip_address = FALSE;
33     
var $user_agent = FALSE;
34     
var $allow_get_array = FALSE;
35     
var $charset = 'iso-8859-1';
36
37     
/* never allowed, string replacement */
38     
var $never_allowed_str = array(
39                                     
'document.cookie' => '[removed]',
40                                     
'document.write' => '[removed]',
41                                     
'.parentNode' => '[removed]',
42                                     
'.innerHTML' => '[removed]',
43                                     
'window.location' => '[removed]',
44                                     
'-moz-binding' => '[removed]',
45                                     
'<!--' => '&lt;!--',
46                                     
'-->' => '--&gt;',
47                                     
'<![CDATA[' => '&lt;![CDATA['
48                                     );
49     
/* never allowed, regex replacement */
50     
var $never_allowed_regex = array(
51                                         
"javascript\s*:" => '[removed]',
52                                         
"expression\s*(\(|&\#40;)" => '[removed]', // CSS and IE
53                                         
"vbscript\s*:" => '[removed]', // IE, surprise!
54                                         
"Redirect\s+302" => '[removed]'
55                                     );
56
57
58     function __construct(){
59         $
this->CI_Input();
60     }
61
62     
/**
63     * Constructor
64     *
65     * Sets whether to globally enable the XSS processing
66     * and whether to allow the $_GET array
67     *
68     * @access
public
69     */

70     function CI_Input()
71     {
72         $
this->use_xss_clean = FALSE;
73         $
this->allow_get_array = TRUE;
74         
// $this->_sanitize_globals();
75     }
76
77     
// --------------------------------------------------------------------
78
79     
/**
80     * Sanitize Globals
81     *
82     * This function does the following:
83     *
84     * Unsets $_GET data (
if query strings are not enabled)
85     *
86     * Unsets all globals
if register_globals is enabled
87     *
88     * Standardizes newline characters to \n
89     *
90     * @access
private
91     * @
return void
92     */

93     function _sanitize_globals()
94     {
95         
// Would kind of be "wrong" to unset any of these GLOBALS
96         $
protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',
97                             
'system_folder', 'application_folder', 'BM', 'EXT', 'CFG', 'URI', 'RTR', 'OUT', 'IN');
98
99         
// Unset globals for security.
100         
// This is effectively the same as register_globals = off
101         
foreach (array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_ENV, (isset($_SESSION) && is_array($_SESSION)) ? $_SESSION : array()) as $global)
102         {
103             
if ( ! is_array($global))
104             {
105                 
if ( ! in_array($global, $protected))
106                 {
107                     unset($GLOBALS[$
global]);
108                 }
109             }
110             
else
111             {
112                 
foreach ($global as $key => $val)
113                 {
114                     
if ( ! in_array($key, $protected))
115                     {
116                         unset($GLOBALS[$key]);
117                     }
118
119                     
if (is_array($val))
120                     {
121                         
foreach($val as $k => $v)
122                         {
123                             
if ( ! in_array($k, $protected))
124                             {
125                                 unset($GLOBALS[$k]);
126                             }
127                         }
128                     }
129                 }
130             }
131         }
132
133         
// Is $_GET data allowed? If not we'll set the $_GET to an empty array
134         
if ($this->allow_get_array == FALSE)
135         {
136             $_GET = array();
137         }
138         
else
139         {
140             $_GET = $
this->_clean_input_data($_GET);
141         }
142
143         
// Clean $_POST Data
144         $_POST = $
this->_clean_input_data($_POST);
145
146         
// Clean $_COOKIE Data
147         
// Also get rid of specially treated cookies that might be set by a server
148         
// or silly application, that are of no use to a CI application anyway
149         
// but that when present will trip our 'Disallowed Key Characters' alarm
150         
// http://www.ietf.org/rfc/rfc2109.txt
151         
// note that the key names below are single quoted strings, and are not PHP variables
152         unset($_COOKIE[
'$Version']);
153         unset($_COOKIE[
'$Path']);
154         unset($_COOKIE[
'$Domain']);
155         $_COOKIE = $
this->_clean_input_data($_COOKIE);
156
157     }
158
159     
// --------------------------------------------------------------------
160
161     
/**
162     * Clean Input Data
163     *
164     * This
is a helper function. It escapes data and
165     * standardizes newline characters to \n
166     *
167     * @access
private
168     * @param
string
169     * @
return string
170     */

171     function _clean_input_data($str)
172     {
173         
if (is_array($str))
174         {
175             $new_array = array();
176             
foreach ($str as $key => $val)
177             {
178                 $new_array[$
this->_clean_input_keys($key)] = $this->_clean_input_data($val);
179             }
180             
return $new_array;
181         }
182
183         
// We strip slashes if magic quotes is on to keep things consistent
184         
if (get_magic_quotes_gpc())
185         {
186             $str = stripslashes($str);
187         }
188
189         
// Should we filter the input data?
190         
if ($this->use_xss_clean === TRUE)
191         {
192             $str = $
this->xss_clean($str);
193         }
194
195         
// Standardize newlines
196         
if (strpos($str, "\r") !== FALSE)
197         {
198             $str = str_replace(array(
"\r\n", "\r"), "\n", $str);
199         }
200
201         
return $str;
202     }
203
204     
// --------------------------------------------------------------------
205
206     
/**
207     * Clean Keys
208     *
209     * This
is a helper function. To prevent malicious users
210     *
from trying to exploit keys we make sure that keys are
211     * only named with alpha-numeric text and a few other items.
212     *
213     * @access
private
214     * @param
string
215     * @
return string
216     */

217     function _clean_input_keys($str)
218     {
219         
if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))
220         {
221             exit(
'Disallowed Key Characters.');
222         }
223
224         
return $str;
225     }
226
227     
// --------------------------------------------------------------------
228
229     
/**
230     * Fetch
from array
231     *
232     * This
is a helper function to retrieve values from global arrays
233     *
234     * @access
private
235     * @param array
236     * @param
string
237     * @param
bool
238     * @
return string
239     */

240     function _fetch_from_array(&$array, $index =
'', $xss_clean = FALSE)
241     {
242         
if ( ! isset($array[$index]))
243         {
244             
return FALSE;
245         }
246
247         
if ($xss_clean === TRUE)
248         {
249             
return $this->xss_clean($array[$index]);
250         }
251
252         
return $array[$index];
253     }
254
255     
// --------------------------------------------------------------------
256
257     
/**
258     * Fetch an item
from the GET array
259     *
260     * @access
public
261     * @param
string
262     * @param
bool
263     * @
return string
264     */

265     function
get($index = '', $xss_clean = FALSE)
266     {
267         
return $this->_fetch_from_array($_GET, $index, $xss_clean);
268     }
269
270     
// --------------------------------------------------------------------
271
272     
/**
273     * Fetch an item
from the POST array
274     *
275     * @access
public
276     * @param
string
277     * @param
bool
278     * @
return string
279     */

280     function post($index =
'', $xss_clean = FALSE)
281     {
282         
return $this->_fetch_from_array($_POST, $index, $xss_clean);
283     }
284
285     
// --------------------------------------------------------------------
286
287     
/**
288     * Fetch an item
from either the GET array or the POST
289     *
290     * @access
public
291     * @param
string The index key
292     * @param
bool XSS cleaning
293     * @
return string
294     */

295     function get_post($index =
'', $xss_clean = FALSE)
296     {
297         
if ( ! isset($_POST[$index]) )
298         {
299             
return $this->get($index, $xss_clean);
300         }
301         
else
302         {
303             
return $this->post($index, $xss_clean);
304         }
305     }
306
307     
// --------------------------------------------------------------------
308
309     
/**
310     * Fetch an item
from the COOKIE array
311     *
312     * @access
public
313     * @param
string
314     * @param
bool
315     * @
return string
316     */

317     function cookie($index =
'', $xss_clean = FALSE)
318     {
319         
return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
320     }
321
322     
// --------------------------------------------------------------------
323
324     
/**
325     * Fetch an item
from the SERVER array
326     *
327     * @access
public
328     * @param
string
329     * @param
bool
330     * @
return string
331     */

332     function server($index =
'', $xss_clean = FALSE)
333     {
334         
return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
335     }
336
337     
// --------------------------------------------------------------------
338
339     
/**
340     * Fetch the IP Address
341     *
342     * @access
public
343     * @
return string
344     */

345     function ip_address()
346     {
347         
if ($this->ip_address !== FALSE)
348         {
349             
return $this->ip_address;
350         }
351         
352         
if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR'))
353         {
354             $proxies = preg_split(
'/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY);
355             $proxies = is_array($proxies) ? $proxies : array($proxies);
356
357             $
this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
358         }
359         elseif ($
this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))
360         {
361             $
this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
362         }
363         elseif ($
this->server('REMOTE_ADDR'))
364         {
365             $
this->ip_address = $_SERVER['REMOTE_ADDR'];
366         }
367         elseif ($
this->server('HTTP_CLIENT_IP'))
368         {
369             $
this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
370         }
371         elseif ($
this->server('HTTP_X_FORWARDED_FOR'))
372         {
373             $
this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
374         }
375
376         
if ($this->ip_address === FALSE)
377         {
378             $
this->ip_address = '0.0.0.0';
379             
return $this->ip_address;
380         }
381
382         
if (strstr($this->ip_address, ','))
383         {
384             $x = explode(
',', $this->ip_address);
385             $
this->ip_address = trim(end($x));
386         }
387
388         
if ( ! $this->valid_ip($this->ip_address))
389         {
390             $
this->ip_address = '0.0.0.0';
391         }
392
393         
return $this->ip_address;
394     }
395
396     
// --------------------------------------------------------------------
397
398     
/**
399     * Validate IP Address
400     *
401     * Updated version suggested
by Geert De Deckere
402     *
403     * @access
public
404     * @param
string
405     * @
return string
406     */

407     function valid_ip($ip)
408     {
409         $ip_segments = explode(
'.', $ip);
410
411         
// Always 4 segments needed
412         
if (count($ip_segments) != 4)
413         {
414             
return FALSE;
415         }
416         
// IP can not start with 0
417         
if ($ip_segments[0][0] == '0')
418         {
419             
return FALSE;
420         }
421         
// Check each segment
422         
foreach ($ip_segments as $segment)
423         {
424             
// IP segments must be digits and can not be
425             
// longer than 3 digits or greater then 255
426             
if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
427             {
428                 
return FALSE;
429             }
430         }
431
432         
return TRUE;
433     }
434
435     
// --------------------------------------------------------------------
436
437     
/**
438     * User Agent
439     *
440     * @access
public
441     * @
return string
442     */

443     function user_agent()
444     {
445         
if ($this->user_agent !== FALSE)
446         {
447             
return $this->user_agent;
448         }
449
450         $
this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
451
452         
return $this->user_agent;
453     }
454
455     
// --------------------------------------------------------------------
456
457     
/**
458     * Filename Security
459     *
460     * @access
public
461     * @param
string
462     * @
return string
463     */

464     function filename_security($str)
465     {
466         $bad = array(
467                         
"../",
468                         
"./",
469                         
"<!--",
470                         
"-->",
471                         
"<",
472                         
">",
473                         
"'",
474                         
'"',
475                         
'&',
476                         
'$',
477                         
'#',
478                         
'{',
479                         
'}',
480                         
'[',
481                         
']',
482                         
'=',
483                         
';',
484                         
'?',
485                         
"%20",
486                         
"%22",
487                         
"%3c", // <
488                         
"%253c", // <
489                         
"%3e", // >
490                         
"%0e", // >
491                         
"%28", // (
492                         
"%29", // )
493                         
"%2528", // (
494                         
"%26", // &
495                         
"%24", // $
496                         
"%3f", // ?
497                         
"%3b", // ;
498                         
"%3d" // =
499                     );
500
501         
return stripslashes(str_replace($bad, '', $str));
502     }
503
504     
// --------------------------------------------------------------------
505
506     
/**
507     * XSS Clean
508     *
509     * Sanitizes data so that Cross Site Scripting Hacks can be
510     * prevented. This function does a fair amount of work but
511     * it
is extremely thorough, designed to prevent even the
512     * most obscure XSS attempts. Nothing
is ever 100% foolproof,
513     * of course, but I haven
't been able to get anything passed
514     * the filter.
515     *
516     * Note: This function should only be used to deal with data
517     * upon submission. It
's not something that should
518     * be used
for general runtime processing.
519     *
520     * This function was based
in part on some code and ideas I
521     * got
from Bitflux: http://blog.bitflux.ch/wiki/XSS_Prevention
522     *
523     * To help develop
this script I used this great list of
524     * vulnerabilities along with a few other hacks I
've
525     * harvested
from examining vulnerabilities in other programs:
526     * http://ha.ckers.org/xss.html
527     *
528     * @access
public
529     * @param
string
530     * @
return string
531     */

532     function xss_clean($str, $is_image = FALSE)
533     {
534         
/*
535         * Is the
string an array?
536         *
537         */

538         
if (is_array($str))
539         {
540             
while (list($key) = each($str))
541             {
542                 $str[$key] = $
this->xss_clean($str[$key]);
543             }
544
545             
return $str;
546         }
547
548         
/*
549         * Remove Invisible Characters
550         */

551         $str = $
this->_remove_invisible_characters($str);
552
553         
/*
554         * Protect GET variables
in URLs
555         */

556
557         
// 901119URL5918AMP18930PROTECT8198
558
559         $str = preg_replace(
'|\&([a-z\_0-9]+)\=([a-z\_0-9]+)|i', $this->xss_hash()."\\1=\\2", $str);
560
561         
/*
562         * Validate standard character entities
563         *
564         * Add a semicolon
if missing. We do this to enable
565         * the conversion of entities to ASCII later.
566         *
567         */

568         $str = preg_replace(
'#(&\#[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str);
569
570         
/*
571         * Validate UTF16 two
byte encoding (x00)
572         *
573         * Just
as above, adds a semicolon if missing.
574         *
575         */

576         $str = preg_replace(
'#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);
577
578         
/*
579         * Un-Protect GET variables
in URLs
580         */

581         $str = str_replace($
this->xss_hash(), '&', $str);
582
583         
/*
584         * URL Decode
585         *
586         * Just
in case stuff like this is submitted:
587         *
588         * <a href=
"http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
589         *
590         * Note: Use rawurldecode() so it does not
remove plus signs
591         *
592         */

593         
//$str = rawurldecode($str);
594
595         
/*
596         * Convert character entities to ASCII
597         *
598         * This permits our tests below to work reliably.
599         * We only convert entities that are within tags since
600         * these are the ones that will pose security problems.
601         *
602         */

603
604         $str = preg_replace_callback(
"/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);
605
606         $str = preg_replace_callback(
"/<\w+.*?(?=>|<|$)/si", array($this, '_html_entity_decode_callback'), $str);
607
608         
/*
609         * Remove Invisible Characters Again!
610         */

611         $str = $
this->_remove_invisible_characters($str);
612
613         
/*
614         * Convert all tabs to spaces
615         *
616         * This prevents strings like
this: ja vascript
617         * NOTE: we deal with spaces between characters later.
618         * NOTE: preg_replace was found to be amazingly slow here
on large blocks of data,
619         * so we use str_replace.
620         *
621         */

622
623         
if (strpos($str, "\t") !== FALSE)
624         {
625             $str = str_replace(
"\t", ' ', $str);
626         }
627
628         
/*
629         * Capture converted
string for later comparison
630         */

631         $converted_string = $str;
632
633         
/*
634         * Not Allowed Under Any Conditions
635         */

636
637         
foreach ($this->never_allowed_str as $key => $val)
638         {
639             $str = str_replace($key, $val, $str);
640         }
641
642         
foreach ($this->never_allowed_regex as $key => $val)
643         {
644             $str = preg_replace(
"#".$key."#i", $val, $str);
645         }
646
647         
/*
648         * Makes PHP tags safe
649         *
650         * Note: XML tags are inadvertently replaced too:
651         *
652         * <?xml
653         *
654         * But it doesn
't seem to pose a problem.
655         *
656         */

657         
if ($is_image === TRUE)
658         {
659             
// Images have a tendency to have the PHP short opening and closing tags every so often
660             
// so we skip those and only do the long opening tags.
661             $str = preg_replace(
'/<\?(php)/i', "&lt;?\\1", $str);
662         }
663         
else
664         {
665             $str = str_replace(array(
'<?', '?'.'>'), array('&lt;?', '?&gt;'), $str);
666         }
667
668         
/*
669         * Compact any exploded words
670         *
671         * This corrects words like: j a v a s c r i p t
672         * These words are compacted back to their correct state.
673         *
674         */

675         $words = array(
'javascript', 'expression', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
676         
foreach ($words as $word)
677         {
678             $temp =
'';
679
680             
for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
681             {
682                 $temp .= substr($word, $i,
1)."\s*";
683             }
684
685             
// We only want to do this when it is followed by a non-word character
686             
// That way valid stuff like "dealer to" does not become "dealerto"
687             $str = preg_replace_callback(
'#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
688         }
689
690         
/*
691         * Remove disallowed Javascript
in links or img tags
692         * We used to
do some version comparisons and use of stripos for PHP5, but it is dog slow compared
693         * to these simplified non-capturing preg_match(), especially
if the pattern exists in the string
694         */

695         
do
696         {
697             $original = $str;
698
699             
if (preg_match("/<a/i", $str))
700             {
701                 $str = preg_replace_callback(
"#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
702             }
703
704             
if (preg_match("/<img/i", $str))
705             {
706                 $str = preg_replace_callback(
"#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str);
707             }
708
709             
if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
710             {
711                 $str = preg_replace(
"#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);
712             }
713         }
714         
while($original != $str);
715
716         unset($original);
717
718         /*
719         * Remove JavaScript Event Handlers
720         *
721         * Note: This code
is a little blunt. It removes
722         * the
event handler and anything up to the closing >,
723         * but it
's unlikely to be a problem.
724         *
725         */

726         $event_handlers = array(
'[^a-z_\-]on\w*','xmlns');
727
728         
if ($is_image === TRUE)
729         {
730             
/*
731             * Adobe Photoshop puts XML metadata
into JFIF images, including namespacing,
732             * so we have to allow
this for images. -Paul
733             */

734             unset($event_handlers[array_search(
'xmlns', $event_handlers)]);
735         }
736
737         $str = preg_replace(
"#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str);
738
739         
/*
740         * Sanitize naughty HTML elements
741         *
742         * If a tag containing any of the words
in the list
743         * below
is found, the tag gets converted to entities.
744         *
745         * So
this: <blink>
746         * Becomes: &lt;blink&gt;
747         *
748         */

749         $naughty =
'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
750         $str = preg_replace_callback(
'#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);
751
752         /*
753         * Sanitize naughty scripting elements
754         *
755         * Similar to above, only instead of looking
for
756         * tags it looks
for PHP and JavaScript commands
757         * that are disallowed. Rather than removing the
758         * code, it simply converts the parenthesis to entities
759         * rendering the code un-executable.
760         *
761         * For example: eval(
'some code')
762         * Becomes: eval&#
40;'some code'&#41;
763         *
764         */

765         $str = preg_replace(
'#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);
766
767         
/*
768         * Final clean up
769         *
770         * This adds a bit of extra precaution
in case
771         * something got through the above filters
772         *
773         */

774         
foreach ($this->never_allowed_str as $key => $val)
775         {
776             $str = str_replace($key, $val, $str);
777         }
778
779         
foreach ($this->never_allowed_regex as $key => $val)
780         {
781             $str = preg_replace(
"#".$key."#i", $val, $str);
782         }
783
784         
/*
785         * Images are Handled
in a Special Way
786         * - Essentially, we want to know that after all of the character conversion
is done whether
787         * any unwanted, likely XSS, code was found. If not, we
return TRUE, as the image is clean.
788         * However,
if the string post-conversion does not matched the string post-removal of XSS,
789         * then it fails,
as there was unwanted XSS code found and removed/changed during processing.
790         */

791
792         
if ($is_image === TRUE)
793         {
794             
if ($str == $converted_string)
795             {
796                 
return TRUE;
797             }
798             
else
799             {
800                 
return FALSE;
801             }
802         }
803
804         
return $str;
805     }
806
807     
// --------------------------------------------------------------------
808
809     
/**
810     * Random Hash
for protecting URLs
811     *
812     * @access
public
813     * @
return string
814     */

815     function xss_hash()
816     {
817         
if ($this->xss_hash == '')
818         {
819             
if (phpversion() >= 4.2)
820                 mt_srand();
821             
else
822                 mt_srand(hexdec(substr(md5(microtime()), -
8)) & 0x7fffffff);
823
824             $
this->xss_hash = md5(time() + mt_rand(0, 1999999999));
825         }
826
827         
return $this->xss_hash;
828     }
829
830     
// --------------------------------------------------------------------
831
832     
/**
833     * Remove Invisible Characters
834     *
835     * This prevents sandwiching
null characters
836     * between ascii characters, like Java\0script.
837     *
838     * @access
public
839     * @param
string
840     * @
return string
841     */

842     function _remove_invisible_characters($str)
843     {
844         
static $non_displayables;
845
846         
if ( ! isset($non_displayables))
847         {
848             
// every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09),
849             $non_displayables = array(
850                                         
'/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15
851                                         
'/%1[0-9a-f]/', // url encoded 16-31
852                                         
'/[\x00-\x08]/', // 00-08
853                                         
'/\x0b/', '/\x0c/', // 11, 12
854                                         
'/[\x0e-\x1f]/' // 14-31
855                                     );
856         }
857
858         
do
859         {
860             $cleaned = $str;
861             $str = preg_replace($non_displayables,
'', $str);
862         }
863         
while ($cleaned != $str);
864
865         
return $str;
866     }
867
868     
// --------------------------------------------------------------------
869
870     
/**
871     * Compact Exploded Words
872     *
873     * Callback function
for xss_clean() to remove whitespace from
874     * things like j a v a s c r i p t
875     *
876     * @access
public
877     * @param type
878     * @
return type
879     */

880     function _compact_exploded_words($matches)
881     {
882         
return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
883     }
884
885     
// --------------------------------------------------------------------
886
887     
/**
888     * Sanitize Naughty HTML
889     *
890     * Callback function
for xss_clean() to remove naughty HTML elements
891     *
892     * @access
private
893     * @param array
894     * @
return string
895     */

896     function _sanitize_naughty_html($matches)
897     {
898         
// encode opening brace
899         $str =
'&lt;'.$matches[1].$matches[2].$matches[3];
900
901         
// encode captured opening or closing brace to prevent recursive vectors
902         $str .= str_replace(array(
'>', '<'), array('&gt;', '&lt;'), $matches[4]);
903
904         
return $str;
905     }
906
907     
// --------------------------------------------------------------------
908
909     
/**
910     * JS Link Removal
911     *
912     * Callback function
for xss_clean() to sanitize links
913     * This limits the PCRE backtracks, making it more performance friendly
914     * and prevents PREG_BACKTRACK_LIMIT_ERROR
from being triggered in
915     * PHP
5.2+ on link-heavy strings
916     *
917     * @access
private
918     * @param array
919     * @
return string
920     */

921     function _js_link_removal($match)
922     {
923         $attributes = $
this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));
924         
return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|javascript\s*&colon|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
925     }
926
927     
/**
928     * JS Image Removal
929     *
930     * Callback function
for xss_clean() to sanitize image tags
931     * This limits the PCRE backtracks, making it more performance friendly
932     * and prevents PREG_BACKTRACK_LIMIT_ERROR
from being triggered in
933     * PHP
5.2+ on image tag heavy strings
934     *
935     * @access
private
936     * @param array
937     * @
return string
938     */

939     function _js_img_removal($match)
940     {
941         $attributes = $
this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));
942         
return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|javascript\s*&colon|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
943     }
944
945     
// --------------------------------------------------------------------
946
947     
/**
948     * Attribute Conversion
949     *
950     * Used
as a callback for XSS Clean
951     *
952     * @access
public
953     * @param array
954     * @
return string
955     */

956     function _convert_attribute($match)
957     {
958         
return str_replace(array('>', '<', '\\'), array('&gt;', '&lt;', '\\\\'), $match[0]);
959     }
960
961     
// --------------------------------------------------------------------
962
963     
/**
964     * HTML Entity Decode Callback
965     *
966     * Used
as a callback for XSS Clean
967     *
968     * @access
public
969     * @param array
970     * @
return string
971     */

972     function _html_entity_decode_callback($match)
973     {
974         $charset = $
this->charset;
975
976         
return $this->_html_entity_decode($match[0], strtoupper($charset));
977     }
978
979     
// --------------------------------------------------------------------
980
981     
/**
982     * HTML Entities Decode
983     *
984     * This function
is a replacement for html_entity_decode()
985     *
986     * In some versions of PHP the native function does not work
987     *
when UTF-8 is the specified character set, so this gives us
988     * a work-around. More info here:
989     * http://bugs.php.net/bug.php?id=
25670
990     *
991     * @access
private
992     * @param
string
993     * @param
string
994     * @
return string
995     */

996     
/* -------------------------------------------------
997     /* Replacement
for html_entity_decode()
998     /* -------------------------------------------------*/

999
1000     
/*
1001     NOTE: html_entity_decode() has a bug
in some PHP versions when UTF-8 is the
1002     character
set, and the PHP developers said they were not back porting the
1003     fix to versions other than PHP
5.x.
1004     */

1005     function _html_entity_decode($str, $charset=
'UTF-8')
1006     {
1007         
if (stristr($str, '&') === FALSE) return $str;
1008
1009         
// The reason we are not using html_entity_decode() by itself is because
1010         
// while it is not technically correct to leave out the semicolon
1011         
// at the end of an entity most browsers will still interpret the entity
1012         
// correctly. html_entity_decode() does not convert entities without
1013         
// semicolons, so we are left with our own little solution here. Bummer.
1014
1015         
if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>=')))
1016         {
1017             $str = @html_entity_decode($str, ENT_COMPAT, $charset);
1018             
// $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
1019             $str = preg_replace_callback(
'~&#x(0*[0-9a-f]{2,5})~i', '_chrhexdec', $str);
1020             
// return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
1021             
return preg_replace_callback('~&#([0-9]{2,4})~', '_chr', $str);
1022         }
1023
1024         
// Numeric Entities
1025         
// $str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str);
1026         $str = preg_replace_callback(
'~&#x(0*[0-9a-f]{2,5});{0,1}~i', '_chrhexdec', $str);
1027         
// $str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str);
1028         $str = preg_replace_callback(
'~&#([0-9]{2,4});{0,1}~', '_chr', $str);
1029
1030         
// Literal Entities - Slightly slow so we do another check
1031         
if (stristr($str, '&') === FALSE)
1032         {
1033             $str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES)));
1034         }
1035
1036         
return $str;
1037     }
1038
1039     
/* callback function added for use in _html_entity_decode */
1040     function _chr($m){
1041         
return chr($m[1]);
1042     }
1043
1044     
/* callback function added for use in _html_entity_decode */
1045     function _chrhexdec($m){
1046         
return chr(hexdec($m[1]));
1047     }
1048     
// --------------------------------------------------------------------
1049
1050     
/**
1051     * Filter Attributes
1052     *
1053     * Filters tag attributes
for consistency and safety
1054     *
1055     * @access
public
1056     * @param
string
1057     * @
return string
1058     */
1059     function _filter_attributes($str)
1060     {
1061         $
out = '';
1062
1063         
if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
1064         {
1065             
foreach ($matches[0] as $match)
1066             {
1067                 $
out .= preg_replace("#/\*.*?\*/#s", '', $match);
1068             }
1069         }
1070
1071         
return $out;
1072     }
1073
1074     
// --------------------------------------------------------------------
1075
1076 }


Gõ tìm kiếm nhanh...